/********************************************************************************************************
 * @file    myudb_usb.c
 *
 * @brief   This is the source file for BLE SDK
 *
 * @author  BLE GROUP
 * @date    06,2022
 *
 * @par     Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *
 *******************************************************************************************************/
#include "drivers.h"
#include "myudb.h"
#include "myudb_usbdesc.h"
#include "common/utility.h"
#include <string.h>
#include "vendor/common/tlkapi_debug.h"

#if (VCD_EN || DUMP_STR_EN || (TLKAPI_DEBUG_ENABLE && TLKAPI_DEBUG_CHANNEL == TLKAPI_DEBUG_CHANNEL_UDB))


typedef struct myudb_cfg
{
    u16 id;
    u16 response_len;

    u8 *response;
    u32 tick_sync;

    u8  stall;
    u8  rptr;
    u16 cmd_len;

} myudb_cfg_t;

myudb_cfg_t myudb = {0x120, 0, 0, 0, 0, 0, 0};

static USB_Request_Header_t control_request;


my_fifo_t *myudb_print_fifo = 0;

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      USB device handling
//-----------------------------------------------------------------------------------------
enum
{
    MYUDB_USB_IRQ_SETUP_REQ = 0,
    MYUDB_USB_IRQ_DATA_REQ,
};

////////////////////////////////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------------------
void myudb_usb_send_response(void)
{
    u16 n;
    if (myudb.response_len < 8) {
        n = myudb.response_len;
    } else {
        n = 8;
    }
    myudb.response_len -= n;
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
    usbhw_reset_ctrl_ep_ptr();
    while (n-- > 0) {
        usbhw_write_ctrl_ep_data(*myudb.response);
        ++myudb.response;
    }
#else
    usb1hw_reset_ctrl_ep_ptr();
    while (n-- > 0) {
        usb1hw_write_ctrl_ep_data(*myudb.response);
        ++myudb.response;
    }
#endif
}

void myudb_usb_prepare_desc_data(void)
{
    u8 value_l = (control_request.wValue) & 0xff;
    u8 value_h = (control_request.wValue >> 8) & 0xff;

    myudb.response     = 0;
    myudb.response_len = 0;

    switch (value_h) {
    case DTYPE_Device:
        myudb.response     = myudb_usbdesc_get_device();
        myudb.response_len = sizeof(USB_Descriptor_Device_t);
        break;

    case DTYPE_Configuration:
        myudb.response     = myudb_usbdesc_get_configuration();
        myudb.response_len = sizeof(MYUDB_USB_Descriptor_Configuration_t);
        break;

    case DTYPE_String:
        if (MYUDB_USB_STRING_LANGUAGE == value_l) {
            myudb.response     = myudb_usbdesc_get_language();
            myudb.response_len = sizeof(LANGUAGE_ID_ENG);
        } else if (MYUDB_USB_STRING_VENDOR == value_l) {
            myudb.response     = myudb_usbdesc_get_vendor();
            myudb.response_len = sizeof(MYUDB_STRING_VENDOR);
        } else if (MYUDB_USB_STRING_PRODUCT == value_l) {
            myudb.response     = myudb_usbdesc_get_product();
            myudb.response_len = sizeof(MYUDB_STRING_PRODUCT);
        } else if (MYUDB_USB_STRING_SERIAL == value_l) {
            myudb.response     = myudb_usbdesc_get_serial();
            myudb.response_len = sizeof(MYUDB_STRING_SERIAL);
        } else {
            myudb.stall = 1;
        }
        break;

    default:
        myudb.stall = 1;
        break;
    }

    if (control_request.wLength < myudb.response_len) {
        myudb.response_len = control_request.wLength;
    }

    return;
}

void myudb_usb_handle_in_class_intf_req(void)
{
    u8 property = control_request.bRequest;
    switch (property) {
    case 0x00:
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
        usbhw_write_ctrl_ep_data(0x00);
#else
        usb1hw_write_ctrl_ep_data(0x00);
#endif
        break;
    default:
        myudb.stall = 1;
        break;
    }
}

void myudb_usb_handle_request(u8 data_request)
{
    u8 bmRequestType = control_request.bmRequestType;
    u8 bRequest      = control_request.bRequest;
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
    usbhw_reset_ctrl_ep_ptr();
#else
    usb1hw_reset_ctrl_ep_ptr();
#endif
    switch (bmRequestType) {
    case (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE):
        if (REQ_GetDescriptor == bRequest) {
            if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
                myudb_usb_prepare_desc_data();
            }
            myudb_usb_send_response();
        }
        break;
    case (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE):
        myudb_usb_handle_in_class_intf_req();
        break;
    case (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_INTERFACE):
        if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
            if (0xc0 == bRequest) { // Get board version
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
                usbhw_reset_ctrl_ep_ptr();
                usbhw_write_ctrl_ep_data(myudb.id);
                usbhw_write_ctrl_ep_data(myudb.id >> 8);
#else
                usb1hw_reset_ctrl_ep_ptr();
                usb1hw_write_ctrl_ep_data(myudb.id);
                usb1hw_write_ctrl_ep_data(myudb.id >> 8);
#endif
            } else {
                myudb.stall = 1;
            }
        }
        break;
    case (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE): // 0xc0
        if (MYUDB_USB_IRQ_SETUP_REQ == data_request) {
            if (0xc0 == bRequest) {                              // Get board version
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
                usbhw_reset_ctrl_ep_ptr();
                usbhw_write_ctrl_ep_data(0x40);
                usbhw_write_ctrl_ep_data(0x25);
                usbhw_write_ctrl_ep_data(0x40);
                usbhw_write_ctrl_ep_data(0x05);
                usbhw_write_ctrl_ep_data(0x03);
                usbhw_write_ctrl_ep_data(0x00);
                usbhw_write_ctrl_ep_data(0x01);
                usbhw_write_ctrl_ep_data(0x00);
#else
                usb1hw_reset_ctrl_ep_ptr();
                usb1hw_write_ctrl_ep_data(0x40);
                usb1hw_write_ctrl_ep_data(0x25);
                usb1hw_write_ctrl_ep_data(0x40);
                usb1hw_write_ctrl_ep_data(0x05);
                usb1hw_write_ctrl_ep_data(0x03);
                usb1hw_write_ctrl_ep_data(0x00);
                usb1hw_write_ctrl_ep_data(0x01);
                usb1hw_write_ctrl_ep_data(0x00);
#endif
            } else if (0xc6 == bRequest) { //
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
                usbhw_reset_ctrl_ep_ptr();
                usbhw_write_ctrl_ep_data(0x04);
#else
                usb1hw_reset_ctrl_ep_ptr();
                usb1hw_write_ctrl_ep_data(0x04);
#endif
            } else {
                myudb.stall = 1;
            }
        }
        break;
    case (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE): // 0x40
        myudb.stall = 1;
        break;
    default:
        myudb.stall = 1;
        break;
    }

    return;
}

void myudb_usb_handle_ctl_ep_setup(void)
{
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
    usbhw_reset_ctrl_ep_ptr();
    control_request.bmRequestType = usbhw_read_ctrl_ep_data();
    control_request.bRequest      = usbhw_read_ctrl_ep_data();
    control_request.wValue        = usbhw_read_ctrl_ep_u16();
    control_request.wIndex        = usbhw_read_ctrl_ep_u16();
    control_request.wLength       = usbhw_read_ctrl_ep_u16();
    myudb.stall                   = 0;
    myudb_usb_handle_request(MYUDB_USB_IRQ_SETUP_REQ);
    if (myudb.stall) {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_STALL);
    } else {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_ACK);
    }
#else
    usb1hw_reset_ctrl_ep_ptr();
    control_request.bmRequestType = usb1hw_read_ctrl_ep_data();
    control_request.bRequest      = usb1hw_read_ctrl_ep_data();
    control_request.wValue        = usb1hw_read_ctrl_ep_u16();
    control_request.wIndex        = usb1hw_read_ctrl_ep_u16();
    control_request.wLength       = usb1hw_read_ctrl_ep_u16();
    myudb.stall                   = 0;
    myudb_usb_handle_request(MYUDB_USB_IRQ_SETUP_REQ);
    if (myudb.stall ) {
      usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_DAT_STALL);
    } else {
      usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_DAT_ACK);
    }
#endif
}

void myudb_usb_handle_ctl_ep_data(void)
{
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
    usbhw_reset_ctrl_ep_ptr();
    myudb.stall = 0;
    myudb_usb_handle_request(MYUDB_USB_IRQ_DATA_REQ);
    if (myudb.stall) {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_STALL);
    } else {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_DAT_ACK);
    }
#else
    usb1hw_reset_ctrl_ep_ptr();
    myudb.stall = 0;
    myudb_usb_handle_request(MYUDB_USB_IRQ_DATA_REQ);
    if (myudb.stall) {
        usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_DAT_STALL);
    } else {
        usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_DAT_ACK);
    }
#endif
}

void myudb_usb_handle_ctl_ep_status(void)
{
#if(MCU_CORE_TYPE != MCU_CORE_TL322X)
    if (myudb.stall) {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_STA_STALL);
    } else {
        usbhw_write_ctrl_ep_ctrl(FLD_EP_STA_ACK);
    }
#else
    if (myudb.stall) {
        usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_STA_STALL);
    } else {
        usb1hw_write_ctrl_ep_ctrl(FLD_USB1_EP_STA_ACK);
    }
#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

_attribute_ram_code_ int myudb_print_fifo_full(void)
{
    u8 n = myudb_print_fifo->wptr - myudb_print_fifo->rptr;
    return n >= myudb_print_fifo->num;
}

_attribute_ram_code_ void usb_send_status_pkt(u8 status, u8 buffer_num, u8 *pkt, u16 len)
{
    //  if (myudb_print_fifo_full()) return;        //skip if overflow

    u8 *p = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
    if (len > (myudb_print_fifo->size - 8)) {
        len = (myudb_print_fifo->size - 8);
    }
    *p++ = len + 2;
    *p++ = (len + 2) >> 8;
    p += 2;
    *p++ = status;
    *p++ = buffer_num;
    while (len--) {
        *p++ = *pkt++;
    }
    myudb_print_fifo->wptr++;
}

_attribute_ram_code_ void usb_send_str_data(char *str, u8 *ph, int n)
{
    //  if (myudb_print_fifo_full()) return;        //skip if overflow
    u32 rie = core_interrupt_disable();

    u8 *ps = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
    u8 *pd = ps;

    extern int   tlk_strlen(const char *str);
    unsigned int ns = str ? tlk_strlen(str) : 0;
    if (ns > myudb_print_fifo->size - 12) {
        ns = myudb_print_fifo->size - 12;
        n  = 0;
    }
    if (n + ns > myudb_print_fifo->size - 12) {
        n = myudb_print_fifo->size - 12 - ns;
    }


    #if (TLKAPI_DEBUG_ENABLE && (TLKAPI_DEBUG_CHANNEL != TLKAPI_DEBUG_CHANNEL_UDB))
        #if 1 //QIU new tool
    int len = ns + n + 5;
    *pd++   = len;
    *pd++   = len >> 8;
    *pd++   = 0;
    *pd++   = 0;

    *pd++ = 0x95; //special mark�� 0xA695
    *pd++ = 0xA6;
    *pd++ = ns;   // string length, 1byte
    *pd++ = n;    // data length, 2 byte
    *pd++ = n >> 8;

    while (ns--) {
        *pd++ = *str++;
    }
    while (n--) {
        *pd++ = *ph++;
    }
            //add a '\n' by UART tool
        #else
    int len = ns + 1;
    *pd++   = len;
    *pd++   = len >> 8;
    *pd++   = 0;
    *pd++   = 0;
    while (ns--) {
        *pd++ = *str++;
    }
    *pd++ = '\n';
        #endif
    #else
    int len = n + ns + 2 + 3;
    *pd++   = len;
    *pd++   = len >> 8;
    *pd++   = 0;
    *pd++   = 0;
    *pd++   = 0x82;
    *pd++   = 8;

    *pd++ = 0x22;
    *pd++ = n;
    *pd++ = n >> 8;

    while (n--) {
        *pd++ = *ph++;
    }
    while (ns--) {
        *pd++ = *str++;
    }
    #endif

    myudb_print_fifo->wptr++;

    core_restore_interrupt(rie);
}

_attribute_ram_code_ void usb_send_str_u8s(char *str, u8 d0, u8 d1, u8 d2, u8 d3)
{
    u8 d[4];
    d[0] = d0;
    d[1] = d1;
    d[2] = d2;
    d[3] = d3;
    usb_send_str_data(str, (u8 *)d, 4);
}

_attribute_ram_code_ void usb_send_str_u32s(char *str, u32 d0, u32 d1, u32 d2, u32 d3)
{
    u32 d[4];
    d[0] = d0;
    d[1] = d1;
    d[2] = d2;
    d[3] = d3;
    usb_send_str_data(str, (u8 *)d, 16);
}

_attribute_ram_code_ void myudb_to_usb(void)
{
    static u16 len = 0;
    static u8 *p   = 0;
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
    if (usbhw_is_ep_busy(MYUDB_EDP_IN_HCI)) {
        return;
    }
#else
    if (usb1hw_is_ep_busy(MYUDB_EDP_IN_HCI)) {
        return;
    }
#endif
    if (!p && (myudb_print_fifo->wptr != myudb_print_fifo->rptr)) //first packet
    {
        p = myudb_print_fifo->p + (myudb_print_fifo->rptr++ & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
        ;
        //len = p[1] + 3;
        len = p[0] + p[1] * 256;
        p += 4;
    }
    if (p) {
        int n = len < 64 ? len : 64;
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
        usbhw_reset_ep_ptr(MYUDB_EDP_IN_HCI);
        for (int i = 0; i < n; i++) {
            usbhw_write_ep_data(MYUDB_EDP_IN_HCI, *p++);
        }
        usbhw_data_ep_ack(MYUDB_EDP_IN_HCI);
#else
        usb1hw_reset_ep_ptr(MYUDB_EDP_IN_HCI);
        usb1hw_write_ep_data(MYUDB_EDP_IN_HCI, p, n);
        usb1hw_data_ep_ack(MYUDB_EDP_IN_HCI);
#endif
        len -= n;
        if (n < 64) {
            p = 0;
        }
    }
}

int usb_send_str_int(char *str, int w)
{
    if (myudb_print_fifo_full()) {
        return -1;
    }
    int len;

    u32  rie = core_interrupt_disable();
    char buf[13], tmp, *p;
    int  u;
    char symbol  = ' ';
    int  int_len = 0;
    int  n       = strlen(str);
    if (n == 0) {
        return -2;
    }

    p  = buf + 12;
    *p = '\0';
    u  = w;
    if (w < 0) {
        symbol = '-';
        u      = -w;
    }
    do { // at least one time..
        tmp  = u % 10;
        *--p = tmp + '0';
        u /= 10;
        int_len++;
    } while (u);


    u8 *pd = myudb_print_fifo->p + (myudb_print_fifo->wptr & (myudb_print_fifo->num - 1)) * myudb_print_fifo->size;
    len    = n + 2 + 1 + 1 + int_len; //str_len + '0x20' + symbol + int_len
    *pd++  = len;
    *pd++  = len >> 8;


    *pd++ = 0;
    *pd++ = 0;
    *pd++ = 0x82;
    *pd++ = 8;

    *pd++ = 0x20;
    while (n--) {
        *pd++ = *str++;
    }
    *pd++ = symbol;
    while (int_len--) {
        *pd++ = *p++;
    }
    myudb_print_fifo->wptr++;
    core_restore_interrupt(rie);
    return len;
}

    #define USB_ENDPOINT_BULK_OUT_FLAG (1 << (MYUDB_EDP_OUT_HCI & 7))

_attribute_ram_code_ int myudb_usb_get_packet(u8 *p)
{
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
    if (reg_usb_ep_irq_status & USB_ENDPOINT_BULK_OUT_FLAG) {
        //clear interrupt flag
        reg_usb_ep_irq_status = USB_ENDPOINT_BULK_OUT_FLAG;
        // read data
        int n                             = reg_usb_ep_ptr(MYUDB_EDP_OUT_HCI);
        reg_usb_ep_ptr(MYUDB_EDP_OUT_HCI) = 0;
        for (int i = 0; i < n; i++) {
            p[myudb.cmd_len++] = reg_usb_ep_dat(MYUDB_EDP_OUT_HCI);
        }
        reg_usb_ep_ctrl(MYUDB_EDP_OUT_HCI) = 1; //ACK
        if (n < 64) {
            n             = myudb.cmd_len;
            myudb.cmd_len = 0;
            return n;
        }
    }
#else
    if (reg_usb1_ep_irq_status & USB_ENDPOINT_BULK_OUT_FLAG) {
        //clear interrupt flag
        reg_usb1_ep_irq_status = USB_ENDPOINT_BULK_OUT_FLAG;

        // read data
        int n = usb1hw_get_ep_ptr(MYUDB_EDP_OUT_HCI);
        usb1hw_reset_ep_ptr(MYUDB_EDP_OUT_HCI);
        usb1hw_read_ep_data(MYUDB_EDP_OUT_HCI, &p[myudb.cmd_len], n);
        usb1hw_data_ep_ack(MYUDB_EDP_OUT_HCI);
//        tlkapi_send_string_data(0, "usb rcv cmd", &p[myudb.cmd_len], n);
        myudb.cmd_len +=n;
        if (n < 64) {
            n   = myudb.cmd_len;
            myudb.cmd_len = 0;
            return n;
        }
    }
#endif
    return 0;
}

func_myudb_hci_cmd_cb_t myudb_hci_cmd_cb = 0;

void myudb_register_hci_cb(void *p)
{
    myudb_hci_cmd_cb = p;
}

func_myudb_hci_cmd_cb_t myudb_hci_debug_cb = 0;

void myudb_register_hci_debug_cb(void *p)
{
    myudb_hci_debug_cb = p;
}

    #define MYHCI_FW_DOWNLOAD 0xfe
int fw_download = 0;

_attribute_ram_code_ int myudb_mem_cmd(u8 *p, int nbyte)
{
    int len = nbyte;
    int cmd = p[0];
    u8  rsp[280];

    int ret = 0;
    //////////////////////////  Memory Read ////////////////////////////////////
    if (cmd == 0x28 && len >= 8) {
        usb_send_status_pkt(0x81, 8, p, 12);
        rsp[0] = 0x29;
        memcpy(rsp + 1, p + 1, 5);
        int type = p[1];
        u32 adr  = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
        int n    = p[6] | (p[7] << 8);
        if (n > 256) {
            n = 256;
        }

        if (type == 0) {
            memcpy(rsp + 6, (void *)(adr | 0), n);
        } else if (type == 1) {
            for (int i = 0; i < n; i++) {
                rsp[i + 6] = analog_read_reg8(adr + i);
            }
        } else if (type == 2 || type == 3) //flash
        {
            flash_read_page(adr, n, rsp + 6);
        }
        usb_send_status_pkt(0x82, 8, rsp, n + 6);
    }
    ////////////////////////  Memory Write ////////////////////////////////////
    else if (cmd == 0x2a && len > 6) {
        usb_send_status_pkt(0x81, 8, p, 12);
        rsp[0] = 0x2b;
        memcpy(rsp + 1, p + 1, 16);
        u8  type = p[1];
        u32 adr  = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
        int n    = len - 6;

        if (type == 0)        //RAM
        {
            memcpy((void *)adr, p + 6, n);
        } else if (type == 1) //Analog Register
        {
            for (int i = 0; i < n; i++) {
                analog_write_reg8(adr + i, p[i + 6]);
            }
        } else if (type == 2) // flash
        {
            if (fw_download && (adr & 0xfff) == 0) {
                flash_erase_sector(adr);
            }
            flash_write_page(adr, n, p + 6);
        } else if (type == 3) {
            int nb = p[6];
            if (n > 1) {
                nb += p[7] << 8;
            }
            if (n > 2) {
                nb += p[8] << 16;
            }
            if (n > 3) {
                nb += p[9] << 24;
            }

            if (nb) {
                for (int i = 0; i < nb; i += 4096) {
                    flash_erase_sector(adr + i);
                }
            } else {
    //flash_erase_chip ();
    #if (MCU_CORE_TYPE == MCU_CORE_TL721X) || (MCU_CORE_TYPE == MCU_CORE_TL322X)
                unsigned int flash_mid = flash_read_mid_with_device_num(BLE_EXT_DRIVER_SLAVE_NUM);
    #else
                unsigned int flash_mid = flash_read_mid();
    #endif

                flash_mid >>= 16;
                flash_mid &= 0xff;
                nb = (1 << (flash_mid + 6));
                for (int i = 0; i < nb; i += 4096) {
                    flash_erase_sector(adr + i);
                }
            }
        } else if (type == MYHCI_FW_DOWNLOAD) {
            core_interrupt_disable();

            myudb_print_fifo->rptr = myudb_print_fifo->wptr;

            //extern void hci_txfifo_set_rptr_reference (int idx);
            //hci_txfifo_set_rptr_reference (1);

            ret = MYHCI_FW_DOWNLOAD;
        }
        usb_send_status_pkt(0x82, 8, rsp, 14);
    } else {
        ret = 1;
    }
    return ret;
}

u8 buff_usb_cmd[320];

_attribute_ram_code_ int myudb_hci_cmd_from_usb(void)
{
    fw_download = 0;
    do {
        int n = myudb_usb_get_packet(buff_usb_cmd);
        if (n) {
            int r = myudb_mem_cmd(buff_usb_cmd, n);

            if (r == MYHCI_FW_DOWNLOAD) {
                fw_download = MYHCI_FW_DOWNLOAD;
            } else if (0x11 == buff_usb_cmd[0] && myudb_hci_debug_cb && !fw_download) {
                myudb_hci_debug_cb(buff_usb_cmd, n);
            } else if (r && myudb_hci_cmd_cb && !fw_download) {
                myudb_hci_cmd_cb(buff_usb_cmd, n);
            }
        }
        if (fw_download) {
            myudb_to_usb();
        }
    } while (fw_download);

    return 0;
}

/////////////////////////////////////////////////////////////////////////
void udb_usb_handle_irq(void)
{
    if (1) { //  do nothing when in suspend. Maybe not unnecessary
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
        u32 irq = usbhw_get_ctrl_ep_irq();
        if (irq & FLD_CTRL_EP_IRQ_SETUP) {
            usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_SETUP);
            myudb_usb_handle_ctl_ep_setup();
            if (!myudb.tick_sync) {
                myudb.tick_sync = clock_time() | 1;
            }
        }
        if (irq & FLD_CTRL_EP_IRQ_DATA) {
            usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_DATA);
            myudb_usb_handle_ctl_ep_data();
        }
        if (irq & FLD_CTRL_EP_IRQ_STA) {
            usbhw_clr_ctrl_ep_irq(FLD_CTRL_EP_IRQ_STA);
            myudb_usb_handle_ctl_ep_status();
        }
        if (usbhw_get_irq_status(USB_IRQ_RESET_STATUS)) {
            usbhw_clr_irq_status(USB_IRQ_RESET_STATUS); //Clear USB reset flag
            myudb_usb_bulkout_ready();
        }
#else
        unsigned int irq = usb1hw_get_ctrl_ep_irq();
         if (irq & FLD_USB1_CTRL_EP_IRQ_SETUP) {
             usb1hw_clr_ctrl_ep_irq(FLD_USB1_CTRL_EP_IRQ_SETUP);
             myudb_usb_handle_ctl_ep_setup();
             if (!myudb.tick_sync) {
                 myudb.tick_sync = clock_time() | 1;
             }
         }
         if (irq & FLD_USB1_CTRL_EP_IRQ_DATA) {
             usb1hw_clr_ctrl_ep_irq(FLD_USB1_CTRL_EP_IRQ_DATA);
             myudb_usb_handle_ctl_ep_data();
         }
         if (irq & FLD_USB1_CTRL_EP_IRQ_STA) {
             usb1hw_clr_ctrl_ep_irq(FLD_USB1_CTRL_EP_IRQ_STA);
             myudb_usb_handle_ctl_ep_status();
         }

         if (usb1hw_get_irq_status(USB1_IRQ_RESET_STATUS)) {
             usb1hw_clr_irq_status(USB1_IRQ_RESET_STATUS); /* clear USB reset flag */
             myudb_usb_bulkout_ready();
         }

#endif
        myudb.stall = 0;
    }

    myudb_to_usb();

    myudb_hci_cmd_from_usb();


    #if (VCD_EN)
    if (myudb.tick_sync && clock_time_exceed(myudb.tick_sync, 10000)) {
        myudb.tick_sync = clock_time() | 1;
        #if (VCD_EN)
        log_sync(SL_STACK_VCD_EN);    //log_event(1, SLEV_timestamp)
        log_tick(SL_STACK_VCD_EN, 0); //log_tick(1, SLET_timestamp)
        #endif
    }
    #endif
}

void myudb_usb_bulkout_ready(void)
{
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
    reg_usb_ep_ctrl(MYUDB_EDP_OUT_HCI) = FLD_EP_DAT_ACK;
#else
    reg_usb1_ep_ctrl(MYUDB_EDP_OUT_HCI) = FLD_USB1_EP_DAT_ACK;
#endif
}

void myudb_usb_init(u16 id, void *p_print)
{
    if (p_print) {
        myudb_print_fifo       = p_print;
        myudb_print_fifo->wptr = myudb_print_fifo->rptr = 0;
    }

    memset(&myudb, 0, sizeof(myudb));

    myudb.id = id;

    /*!< usb init */
    #if (MCU_CORE_TYPE == MCU_CORE_TL751X)
    //enable USB manual interrupt(in auto interrupt mode,USB device would be USB printer device)
    usbhw_init();
    /* set control endpoint size */
    usbhw_set_ctrl_ep_size(SIZE_64_BYTE);
    #endif

    #if (MCU_CORE_TYPE == MCU_CORE_TL321X || MCU_CORE_TYPE == MCU_CORE_TL721X)
    usbhw_init();
    /* set control endpoint size */
    usbhw_set_ctrl_ep_size(SIZE_64_BYTE);
    #endif

    #if (MCU_CORE_TYPE == MCU_CORE_TL321X || MCU_CORE_TYPE == MCU_CORE_TL751X)
    usbhw_enable_hw_feature(FLD_USB_AUTO_HALT_CLR | FLD_USB_AUTO_HALT_STALL);
    #endif

    #if (MCU_CORE_TYPE == MCU_CORE_TL322X)
    usb1hw_init();
    #endif

    /*!< usb endpoint init */
#if (MCU_CORE_TYPE != MCU_CORE_TL322X)
    /* set data endpoint buffer size and addr */
    usbhw_set_eps_max_size(MYUDB_EDP_INOUT_SIZE); /* max 64 */
    usbhw_set_ep_addr(MYUDB_EDP_IN_VCD, 0);
    usbhw_set_ep_addr(MYUDB_EDP_IN_HCI, MYUDB_EDP_INOUT_SIZE);
    usbhw_set_ep_addr(MYUDB_EDP_OUT_HCI, MYUDB_EDP_INOUT_SIZE + MYUDB_EDP_INOUT_SIZE);

    //enable USB endpoint 8 FIFO mode
    usbhw_set_ep8_fifo_mode();
    reg_usb_mdev &= ~BIT(3);

    usbhw_enable_manual_interrupt(FLD_CTRL_EP_AUTO_STD | FLD_CTRL_EP_AUTO_DESC);
    usbhw_data_ep_ack(MYUDB_EDP_OUT_HCI);
    usbhw_data_ep_ack(MYUDB_EDP_IN_HCI); //add log 1st log info
#else
    reg_usb1_ep_max_size    = (128 >> 2);
    reg_usb1_ep8_send_thres = 0x40;
    usb1hw_set_ep_addr(MYUDB_EDP_IN_HCI, 128);
    usb1hw_set_ep_addr(MYUDB_EDP_OUT_HCI, 192);
    usb1hw_set_ep_addr(MYUDB_EDP_IN_VCD, 0);
    reg_usb1_ep8_fifo_mode = 1;
    reg_usb1_mdev &= ~BIT(3); /* vendor command: bRequest[7] = 0. */
    usb1hw_enable_manual_interrupt(FLD_USB1_CTRL_EP_AUTO_STD | FLD_USB1_CTRL_EP_AUTO_DESC);
    reg_usb1_ep_ctrl(MYUDB_EDP_OUT_HCI) = FLD_USB1_EP_DAT_ACK;
    reg_usb1_ep_ctrl(MYUDB_EDP_IN_HCI) = FLD_USB1_EP_DAT_ACK;

    usb1hw_set_eps_en(BIT(MYUDB_EDP_IN_HCI) | BIT(MYUDB_EDP_OUT_HCI) | BIT(MYUDB_EDP_IN_VCD & 0x07));
#endif

}


#endif
